#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/wait.h>

#define MARK ":"
#define LABLE "#"
#define DELIM " "
#define LINE_SIZE 1024
#define ARGC_SIZE 32
#define EXIT_CODE 44

int lastcode = 0;
int quit = 0;
extern char **environ;
char commandline[LINE_SIZE];
char *argv[ARGC_SIZE];          
char myenv[LINE_SIZE];
char pwd[LINE_SIZE];

const char* getusername()
{
    return getenv("USER");
}

const char* gethostname()
{
    return getenv("HOSTNAME");
}

void getpwd()
{
    getcwd(pwd, sizeof(pwd));
    const char* home = getenv("HOME"); // 获取用户主目录
   
    if (home != NULL && strcmp(pwd, home) == 0) 
    {        
        // 如果当前目录等于用户主目录，则返回 "~"
        strcpy(pwd, "~");
    }
    else if (home != NULL && strncmp(pwd, home, strlen(home)) == 0) {
        // 如果当前目录是用户主目录的子目录，则替换主目录部分为 "~"
        static char relative_path[LINE_SIZE];
        snprintf(relative_path, sizeof(relative_path), "~%s", pwd + strlen(home));
        strcpy(pwd, relative_path);     
    }
}

void interact(char* cline, int size)
{
    getpwd();
    printf("%s@%s"MARK"%s"LABLE" ", getusername(), gethostname(), pwd);
    char* s = fgets(cline, size, stdin);
    assert(s);
    // printf("echo: %s", s); // 验证能否接收命令以及命令行参数
    cline[strlen(cline)-1] = '\0';
}

int splitstring(char* cline, char* _argv[])
{
    int i = 0;
    argv[i++] = strtok(cline, DELIM);
    while(_argv[i++] = strtok(NULL, DELIM));
    return i - 1;
}

int buildCommand(char* _argv[], int _argc)
{
    if(_argc == 2 && strcmp(_argv[0], "cd") == 0)
    {
        getpwd();
        chdir(_argv[1]);
        sprintf(getenv("PWD"), "%s", pwd);
        return 1;
    }
    else if(_argc == 2 && strcmp(_argv[0], "export") == 0)
    {
        strcpy(myenv, _argv[1]);
        putenv(myenv);
        return 1;
    }
    else if(_argc == 2 && strcmp(_argv[0], "echo") == 0)
    {
        if(strcmp(_argv[1], "$?") == 0)
        {
            printf("%d\n", lastcode);
            lastcode = 0;
        }
        else if(*_argv[1] == '$')
        {
            char* val = getenv(_argv[1] + 1);
            if(val) printf("%s\n", val);
        }
        else printf("%s\n", _argv[1]);
        return 1;
    }
    if(strcmp(_argv[0], "ls") == 0)
    {
        _argv[_argc++] = "--color";
        _argv[_argc] = NULL;
    }

    return 0;
}

void normalExcute(char* _argv[])
{
    pid_t id = fork();
    if(id < 0)
    {
        perror("fork");
        return;
    }
    if(id == 0)
    {
        execvpe(_argv[0], _argv, environ);
        exit(EXIT_CODE);
    }
    else
    {
        int status = 0;
        int rid = waitpid(id, &status, 0);
        if(id == rid) lastcode = WEXITSTATUS(status);
    }
}


int main()
{
    while(!quit)
    {
        // 1、交互获取命令行参数
        interact(commandline, sizeof(commandline)); 
        // 2、指令截取
        int argc = splitstring(commandline, argv);
        // 3、指令判断
        if(argc == 0) continue;
        // 4、执行内建命令
        int n = buildCommand(argv, argc);
        // 5、执行普通指令
        if(!n) normalExcute(argv);
    }
    return 0;
}

